package com.github.tommas.admintpl.service;

import com.github.tommas.admintpl.bean.model.Permission;
import com.github.tommas.admintpl.bean.model.PermissionRestriction;
import com.github.tommas.admintpl.bean.model.Role;
import com.github.tommas.admintpl.bean.model.RolePermission;
import com.github.tommas.admintpl.bean.vo.AssignedPermission;
import com.github.tommas.admintpl.bean.vo.PaginationQuery;
import com.github.tommas.admintpl.bean.vo.PermissionInfo;
import com.github.tommas.admintpl.bean.vo.SearchRoleParam;
import com.github.tommas.admintpl.common.PaginationData;
import com.github.tommas.admintpl.dao.PermissionMapper;
import com.github.tommas.admintpl.dao.RoleMapper;
import com.github.tommas.admintpl.mybatis.Context;
import com.github.tommas.admintpl.security.permission.RestrictedPermissionResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class RoleService {
    @Autowired
    RoleMapper roleMapper;

    @Autowired
    PermissionMapper permissionMapper;

    public PaginationData<Role> getRoleList(PaginationQuery<SearchRoleParam> pq) {
        return PaginationData.createFromQuery(
                pq, () -> roleMapper.searchRoleList());
    }

    public Role createRole(Role role) {
        roleMapper.createRole(Context.insertContext(role), role);
        return role;
    }

    public Role updateRole(Integer id, Role role) {
        role.setId(id);
        int result = roleMapper.updateRole(Context.updateContext(role), role);
        if (result == 0) {
            return null;
        }

        return role;
    }

    @Transactional
    public boolean deleteRole(int id) {
        roleMapper.deleteRolePermissions(id);
        int result = roleMapper.deleteRole(Context.deleteContext(), id);
        return result != 0;
    }

    public List<PermissionInfo> getPermissions() {
        Map<Integer, List<PermissionRestriction>> prmap = new HashMap<>();
        for (PermissionRestriction pr : permissionMapper.searchPermissionRestrictions()) {
            List<PermissionRestriction> l = prmap.get(pr.getPermissionId());
            if (l == null) {
                l = new ArrayList<>();
                prmap.put(pr.getPermissionId(), l);
            }
            l.add(pr);
        }

        List<PermissionInfo> permissions = new ArrayList<>();
        for (Permission permission : permissionMapper.searchPermissions()) {
            PermissionInfo i = new PermissionInfo();
            i.setPermission(permission);
            i.setRestrictions(prmap.get(permission.getId()));
            permissions.add(i);
        }

        return permissions;
    }

    @Transactional
    public boolean assignRolePermission(Integer roleId, List<AssignedPermission> permissions) {
        roleMapper.deleteRolePermissions(roleId);

        List<RolePermission> rolePermissions = new ArrayList<>(permissions.size());
        for (AssignedPermission p : permissions) {
            RolePermission rp = new RolePermission();
            rp.setPermissionId(p.getPermissionId());
            rp.setRoleId(roleId);
            List<String> restrictions = p.getRestrictions();
            if (restrictions != null && !restrictions.isEmpty()) {
                rp.setRestrictions(String.join(RestrictedPermissionResolver.ATTRIBUTE_DIVIDER, restrictions));
            }

            rolePermissions.add(rp);
        }

        return roleMapper.insertRolePermissions(rolePermissions) > 0;
    }
}
